let a1:symbol = Symbol(123); // Symbol类型
let a2:symbol = Symbol(123); // Symbol类型
console.log(a1 === a2); // false，因为每次创建的Symbol都是唯一的

// for的话，会去全局symbol注册表中查找是否有相同的Symbol，如果有则返回同一个Symbol
let a3 = Symbol.for('123'); // 全局Symbol注册表
let a4 = Symbol.for('123'); // 全局Symbol注册表
console.log(a3 === a4); // true，因为Symbol.for会返回同一个Symbol
console.log(Symbol.for('123') === Symbol.for('123')); // true，因为Symbol.for会返回同一个Symbol
// 解决属性key重复的问题
let obj = {
    name: '张三',
    [a1]: '123',
    [a2]: '456',
}
console.log(obj);

// for in 遍历对象时，Symbol类型的属性不会被遍历到
console.log('-----for in 遍历对象-----');
for (let key in obj) {
    console.log(key);
}

console.log(Object.keys(obj)); // ['name']，Symbol类型的属性不会被遍历到

console.log(Object.getOwnPropertyNames(obj)); // ['name']，Symbol类型的属性不会被遍历到
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(123), Symbol(123)] 但是读取不到name属性
// Reflect.ownKeys(obj) 反射
Reflect.ownKeys(obj); // ['name', Symbol(123), Symbol(123)]，可以获取所有属性，包括Symbol类型的属性

// 生成器
function* gen() {
    yield Promise.resolve(10);
    yield 2;
    yield 3;
    yield 'ceshi'
}
let g = gen();
// 不管同步还是异步，next方法返回的都是一个对象 {value: any, done: boolean}按顺序执行
console.log(g.next()); // { value: Promise { 10 }, done: false }
console.log(g.next()); // { value: 2, done: false }
console.log(g.next()); // { value: 3, done: false }
console.log(g.next()); // { value: 'ceshi', done: false }
console.log(g.next()); // { value: undefined, done: true } 表示迭代结束

// 迭代器

let set: Set<number> = new Set([1,1,2,2,3,4,5]); //天然去重
let map: Map<any, any> = new Map()
map.set('a', 1);
map.set('b', 2);
let arr: number[] = [1, 2, 3];
map.set(arr, 4);

function arg() {
    console.log(arguments); //  伪数组
}

// 迭代器
// 迭代器的语法糖 for of
// for of 对对象不可用
function each(value: any) {
    const it:any = value[Symbol.iterator]();
    let next: any = { done: false}
    while (!next.done) {
        next = it.next();
        if (!next.done) {
            console.log(next.value);
        }
    }
}
each([1,2,3]);
each('abc');
each(new Set([1,2,3]));
each(new Map([[1,'a'],[2,'b'],[3,'c']]));

// 解构 原理也是迭代器 iterator
const [a,b] = [1,2];
const as = [1, 2, 3]
// ... 原理也是迭代器 iterator
const ss = [...as]

// 泛型
function numArr(a: number, b: number):number[] {
    return [a, b];
}
function strArr(a: string, b: string):string[] {
    return [a, b];
}

function getArr<T>(a: T, b: T):T[] {
    return [a, b];
}

getArr(1, 2)
getArr('1', '2')

// type 使用泛型
type A<T> = string | number | T;
let ase: A<boolean> = true;
ase = 1;
ase = '1';

// interface 使用泛型
interface B<T> {
    name: string;
    age: number;
    sex: T;
}
let bse: B<boolean> = {
    name: '1',
    age: 1,
    sex: true
}

function add<T, K>(a: T, b: K): Array<T | K> {
  return [a, b];
}
// 还可以为泛型赋默认类型
function add2<T = number, K = number>(a: T, b: K): Array<T | K> {
  return [a, b];
}
// add2()  //这个时候默认参数为number类型，单参数为空会报错，好像默认类型没啥用
add2(1, '1')

// 泛型约束
// function add3<T>(a: T, b: T): T {
//   return a + b;  // 会报错，如果T为undefined，没法相加
// }
function add3<T extends number>(a: T, b: T){
  return a + b;  // 会报错，如果T为undefined，没法相加，返回值类型为T会报错，因为T为number类型
}

interface Len {
    length: number;
}

function fn<T extends Len>(a: T) {
    return a.length;
}

let obj2 = {
    name: 'xiaoming',
    age: 18
}

type Key = keyof typeof obj2; // 获取对象obj2的key的类型，返回类型为"name" | "age"

// 泛型约束  第二个参数必须是第一个参数对象的key
function obj3<T extends object, K extends keyof T>(obj: T, key: K) {
    return obj[key];
}
obj3(obj2, 'age')

// 泛型 为Data设置成可选参数
interface Data {
    name: string;
    age: number;
    sex: boolean;
    height: number;
}

// 循环遍历 for in for(let key in obj)，为接口重新定义类型
type Options<T extends object> = {
    [P in keyof T]?: T[P];
}
type Bo = Options<Data>;